package com.lubase.core.service.flowform.impl;

import com.alibaba.fastjson.JSON;
import com.lubase.core.entity.DmCustomFormEntity;
import com.lubase.core.service.CustomFormDataService;
import com.lubase.core.service.flowform.WorkFlowAdapterService;
import com.lubase.core.service.flowform.model.*;
import com.lubase.model.DbEntity;
import com.lubase.model.DbField;
import com.lubase.model.EAccessGrade;
import com.lubase.orm.exception.ParameterNotFoundException;
import com.lubase.orm.exception.WarnCommonException;
import com.lubase.orm.model.DbCollection;
import com.lubase.orm.model.LoginUser;
import com.lubase.orm.service.AppHolderService;
import com.lubase.orm.service.DataAccess;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class WorkFlowAdapterServiceImpl implements WorkFlowAdapterService {
    @Autowired
    RestTemplate restTemplate;

    @Value("${lubase.wf-api-server:}")
    private String urlTemplate;

    @Autowired
    AppHolderService appHolderService;
    /**
     * 评分数据存储的key
     */
    private String ratingDataStr = "_rating_data";
    @Autowired
    CustomFormDataService customFormDataService;
    @Autowired
    DataAccess dataAccess;

    @SneakyThrows
    @Override
    public Integer startWfByApi(String serviceId, String dataId, String userId) {
        if (StringUtils.isEmpty(serviceId) || StringUtils.isEmpty(dataId) || StringUtils.isEmpty(userId)) {
            return 0;
        }
        String url = String.format("%s/wftEngine/manualStart", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("serviceId", serviceId);
        map.add("dataId", dataId);
        map.add("userId", userId);
        HttpHeaders headers = new HttpHeaders();
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("启动流程错误，通过接口启动流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return 1;
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("提交流程报错" + url, exception);
            throw new WarnCommonException("提交流程报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer runWfByApi(WFCmdRunModel runModel) {
        if (StringUtils.isEmpty(runModel.getOInsId()) || StringUtils.isEmpty(runModel.getCmdId())) {
            throw new ParameterNotFoundException("oInsId和cmdId不能为空");
        }
        String url = String.format("%s/wftEngine/run", urlTemplate);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<WFCmdRunModel> formEntity = new HttpEntity<>(runModel, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程流转报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return 1;
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程流转报错" + url, exception);
            throw new WarnCommonException("流程流转报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer restartWf(String oInsId, String userId) {
        if (StringUtils.isEmpty(oInsId) || StringUtils.isEmpty(userId)) {
            throw new ParameterNotFoundException("oInsId和userId不能为空");
        }
        String url = String.format("%s/wftEngine/restart", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("oInsId", oInsId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程再次提交报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return 1;
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程再次提交报错" + url, exception);
            throw new WarnCommonException("流程再次提交报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer saveData(WFCmdRunModel runModel) {
        if (StringUtils.isEmpty(runModel.getOInsId()) || runModel.getData() == null) {
            throw new ParameterNotFoundException("oInsId和data不能为空");
        }
        // 1、如果有cmdMemo，则保存cmdMemo
        if (!StringUtils.isEmpty(runModel.getCmdMemo())) {
            saveProcessMemo(runModel);
        }
        // 2、根据流程节点设置保存表单数据
        String url = String.format("%s/wftEngine/getTaskSetting", urlTemplate);

        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());

        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("oInsId", runModel.getOInsId());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程saveProcessMemo报错，通过接口流转流程返回值不应该为空");
            }
            if (!result.getSuccess().equals(1)) {
                throw new WarnCommonException(result.getMessage());
            }
            CustomPageSetting customPageSetting = new CustomPageSetting();
            if (result.getData() != null) {
                try {
                    customPageSetting = JSON.parseObject(JSON.toJSONString(result.getData()), CustomPageSetting.class);
                } catch (Exception e) {
                    log.error("流程saveProcessMemo报错，解析自定义页面配置出错", e);
                }
            }
            // 根据自定义页面配置，获取需要保存的字段，并保存数据
            return saveBizData(runModel, customPageSetting);
        } catch (Exception exception) {
            log.error("流程saveProcessMemo报错" + url, exception);
            throw new WarnCommonException("流程saveProcessMemo报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    private Integer saveBizData(WFCmdRunModel runModel, CustomPageSetting customPageSetting) {
        if (customPageSetting == null) {
            return 0;
        }
        //1、更新评分表单数据
        if (runModel.getData().containsKey(ratingDataStr) && runModel.getData().get(ratingDataStr) != null && !StringUtils.isEmpty(customPageSetting.getRatingForm())) {
            DmCustomFormEntity ratingForm = customFormDataService.selectById(customPageSetting.getRatingForm());
            DbEntity ratingEntity = JSON.parseObject(runModel.getData().get(ratingDataStr).toString(), DbEntity.class);
            if (ratingEntity != null) {
                DbCollection collection = dataAccess.getEmptyData(ratingForm.getTable_code());
                collection.getData().add(ratingEntity);
                collection.setClientMode();
                collection.getTableInfo().setFieldList(customFormDataService.getFormFieldSetting(ratingForm));
                dataAccess.update(collection);
            }
        }
        if (StringUtils.isEmpty(customPageSetting.getBizForm())) {
            throw new WarnCommonException("数据异常：流程表单未配置，请联系管理员");
        }
        DmCustomFormEntity formEntity = customFormDataService.selectById(customPageSetting.getBizForm());
        if (null == formEntity) {
            throw new WarnCommonException(String.format("表单%s不存在", customPageSetting.getBizForm()));
        }
        DbCollection collection = dataAccess.getEmptyData(formEntity.getTable_code());
        collection.getData().add(runModel.getData());
        collection.setClientMode();
        // 2、更新表单信息
        // 拼接流程任务节点字段可更新权限设置
        List<DbField> taskFieldList = getTaskNodeFormField(customFormDataService.getFormFieldSetting(formEntity), customPageSetting.getFieldSetting());
        collection.getTableInfo().setFieldList(taskFieldList);
        // 3、调用dataAccess的更新方法，此方法会验证数据权限
        return dataAccess.update(collection);
    }

    public List<DbField> getTaskNodeFormField(List<DbField> formFieldList, List<WfTaskFieldModel> taskFieldModelList) {
        if (taskFieldModelList == null || taskFieldModelList.isEmpty()) {
            return formFieldList;
        }
        Map<String, WfTaskFieldModel> taskFieldList = new HashMap<>();
        for (WfTaskFieldModel field : taskFieldModelList) {
            taskFieldList.put(field.getId(), field);
        }
        //设置表单资源编辑属性
        Integer settingTag = 1;
        for (DbField field : formFieldList) {
            if (!taskFieldList.containsKey(field.getId())) {
                continue;
            }
            WfTaskFieldModel mapField = taskFieldList.get(field.getId());
            if (settingTag.equals(mapField.getHidden())) {
                field.setVisible(EAccessGrade.Invisible.getIndex());
            } else if (settingTag.equals(mapField.getReadonly())) {
                field.setVisible(EAccessGrade.Read.getIndex());
            }
            if (settingTag.equals(mapField.getRequired())) {
                field.setIsNull(0);
            }
            //表单字段可编辑字段默认均不再处理
            if (field.getFieldAccess().getIndex() > EAccessGrade.Read.getIndex()) {
                field.setColDefault("");
            }
        }
        return formFieldList;
    }

    @SneakyThrows
    private void saveProcessMemo(WFCmdRunModel runModel) {
        String url = String.format("%s/wftEngine/saveProcessMemo", urlTemplate);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<WFCmdRunModel> formEntity = new HttpEntity<>(runModel, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程saveProcessMemo报错，通过接口流转流程返回值不应该为空");
            }
            if (!result.getSuccess().equals(1)) {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程saveProcessMemo报错" + url, exception);
            throw new WarnCommonException("流程saveProcessMemo报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Object getApprovalForm(String oInsId) {
        return getApprovalForm(oInsId, false);
    }

    @Override
    public Object getApprovalFormFromApp(String oInsId) {
        return getApprovalForm(oInsId, true);
    }


    @SneakyThrows
    private Object getApprovalForm(String oInsId, Boolean isApp) {
        if (StringUtils.isEmpty(oInsId)) {
            throw new ParameterNotFoundException("oInsId");
        }
        String url = String.format("%s/wftEngine/getApprovalForm", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("oInsId", oInsId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        if (isApp) {
            headers.add("isApp", "1");
        }
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程getApprovalForm报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程getApprovalForm报错" + url, exception);
            throw new WarnCommonException("流程getApprovalForm报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Object getApprovalHistoryForm(String fInsId, String oInsId) {
        if (StringUtils.isEmpty(fInsId)) {
            throw new ParameterNotFoundException("fInsId");
        }
        String url = String.format("%s/wftEngine/getApprovalHistoryForm", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("fInsId", fInsId);
        map.add("oInsId", oInsId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程getApprovalHistoryForm报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程getApprovalHistoryForm报错" + url, exception);
            throw new WarnCommonException("流程getApprovalHistoryForm报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public List<ReturnInfoModel> getReturnBackTaskList(String fInsId) {
        if (StringUtils.isEmpty(fInsId)) {
            throw new ParameterNotFoundException("fInsId");
        }
        String url = String.format("%s/wftMonitor/getReturnBackTaskList", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("fInsId", fInsId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程getReturnBackTaskList报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return (List<ReturnInfoModel>) result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程getReturnBackTaskList报错" + url, exception);
            throw new WarnCommonException("流程getReturnBackTaskList报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public List<TransferInfoModel> getCurrentApprovalUser(String fInsId) {
        if (StringUtils.isEmpty(fInsId)) {
            throw new ParameterNotFoundException("fInsId");
        }
        String url = String.format("%s/wftMonitor/getTransferUserList", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("fInsId", fInsId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程getCurrentApprovalUser报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return (List<TransferInfoModel>) result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程getCurrentApprovalUser报错" + url, exception);
            throw new WarnCommonException("流程getCurrentApprovalUser报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer returnBack(String fInsId, String taskId, String memo, String operatorUserId) {
        String url = String.format("%s/wftMonitor/returnBack", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("fInsId", fInsId);
        map.add("taskId", taskId);
        map.add("memo", memo);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程returnBack报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return (Integer) result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程returnBack报错" + url, exception);
            throw new WarnCommonException("流程returnBack报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer giveUp(LoginUser userInfo, String fInsId, String memo) {
        String url = String.format("%s/wftMonitor/giveUp", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("fInsId", fInsId);
        map.add("memo", memo);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程giveUp报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return (Integer) result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程giveUp报错" + url, exception);
            throw new WarnCommonException("流程giveUp报错" + exception.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public Integer transfer(String oInsId, String operatorUserId, String toUserId) {
        String url = String.format("%s/wftMonitor/transfer", urlTemplate);
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("oInsId", oInsId);
        map.add("toUserId", toUserId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", appHolderService.getUser().getToken());
        HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(map, headers);
        try {
            log.debug(formEntity.toString());
            RemoteCallbackModel result = restTemplate.postForObject(url, formEntity, RemoteCallbackModel.class);
            if (result == null || result.getSuccess() == null) {
                throw new WarnCommonException("流程transfer报错，通过接口流转流程返回值不应该为空");
            }
            if (result.getSuccess().equals(1)) {
                return (Integer) result.getData();
            } else {
                throw new WarnCommonException(result.getMessage());
            }
        } catch (Exception exception) {
            log.error("流程transfer报错" + url, exception);
            throw new WarnCommonException("流程transfer报错" + exception.getMessage());
        }
    }
}
